package p17_从advisor到aspect;

import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

import java.util.List;

/**
 * aspect，最终变成一个个advisor
 * 这是类继承AnnotationAwareAspectJAutoProxyCreator，是为了调用内部方法
 */
public class _1_Aspect和Advisor extends AnnotationAwareAspectJAutoProxyCreator {
    public static void main(String[] args) throws NoSuchMethodException {
        GenericApplicationContext context = new GenericApplicationContext();
        //添加bean工厂后处理器
        context.registerBean("aspect1", MyAspect.class);
        context.registerBean("config", MyAdvisor.class);
        context.registerBean("target1", Target1.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.registerBean(_1_Aspect和Advisor.class);
        /**
         * 高级切面和低级切面都注册进了容器，还需要一个bean后处理器(AnnotationAwareAspectJAutoProxyCreator)
         * 该bean后处理器在bean生命周期的某个阶段根据切面创建代理，创建成功就使用该代理替代bean(bean生命周期的某个方法的返回值会替代原始bean)
         * AnnotationAwareAspectJAutoProxyCreator实现了这两个扩展点: 创建 -> (*)依赖注入 -> 初始化(*)
         */
        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
        context.refresh();
        //这里得到的target1已经是增强后的代理类了
//        Target1 target1 = context.getBean("target1", Target1.class);
//        target1.foo();

        /**
         * AnnotationAwareAspectJAutoProxyCreator这个后处理器是如何工作的呢?
         * AnnotationAwareAspectJAutoProxyCreator中有两个重要方法来完成代理的创建
         *  1.findEligibleAdvisors
         *      根据目标类找到有资格的Advisor(Aspect则会转化为Advisor).第一个参数是目标类class，第二个参数是目标类再容器中名称(这是主动调用，所以随便传)
         *      返回从容器中找到的所有有资格的Advisor集合对象
         *  2.wrapIfNecessary
         *      内部调用了findEligibleAdvisors，只要返回的集合不会空，则表示需要创建代理，并将findEligibleAdvisors返回的advisor与目标方法封装成一个调用链作为代理类的代理方法
         *      需要两个参数:目标对象(容器内可以直接获取)，bean名称，cacheKey
         *      返回值：需要创建代理时，返回一个代理类，否则返回目标类本身
         * 在一切开始之前，AnnotationAwareAspectJAutoProxyCreator会将aspect转为advisor，然后收集所有advisor
         */
        //"Aspect和Advisor"继承了AnnotationAwareAspectJAutoProxyCreator，故而两个类可以认为等价
        _1_Aspect和Advisor creator = context.getBean(_1_Aspect和Advisor.class);
        //AnnotationAwareAspectJAutoProxyCreator会拿着目标类，去和所有advisor一个一个对比，看哪个advisor适合当前目标类，并返回所有合适的advisor
        //AnnotationAwareAspectJAutoProxyCreator这个bean后处理器收集到所有合适的advisor集合后，看这个集合是不是为空，为空则说明不需要增强，则返回原始bean，否则返回代理bean顶替到原始bean
        List<Advisor> advisors = creator.findEligibleAdvisors(Target1.class, "target1");
        //System.out.println(advisors);

        //p1是生成的代理对象
        Target1 p1 = (Target1) creator.wrapIfNecessary(new Target1(), "target1", "target1");
        //p2是Target2原始类的对象，因为没有一个advisor适合target2
        Target2 p2 = (Target2) creator.wrapIfNecessary(new Target2(), "target2", "target2");
        p1.foo();
        p2.bar();

    }

    static class Target1 {
        public void foo() {
            System.out.println("target1的foo...");
        }
    }

    static class Target2 {
        public void bar() {
            System.out.println("target2的bar...");
        }
    }
}
